package edu.pku.sei.mte.compositetrans.agg;

import java.util.Vector;

import org.w3c.dom.Element;

import agg.xt_basis.BaseFactory;
import agg.xt_basis.CompletionStrategySelector;
import agg.xt_basis.DefaultGraTraImpl;
import agg.xt_basis.GraGra;
import agg.xt_basis.GraTraEvent;
import agg.xt_basis.GraTraEventListener;
import agg.xt_basis.LayeredGraTraImpl;
import agg.xt_basis.MorphCompletionStrategy;
import agg.xt_basis.TypeException;
import edu.pku.sei.mte.compositetrans.TResult;
import edu.pku.sei.mte.compositetrans.UniTController;
import edu.pku.sei.mte.compositetrans.configuration.ModelSpec;
import edu.pku.sei.mte.compositetrans.configuration.TransDescriptor;
import edu.pku.sei.mte.utilities.ModelFormat;
import edu.pku.sei.mte.utilities.Utility;

public class AGGController extends UniTController implements GraTraEventListener {

	private GraGra graphGrammar;
	private MorphCompletionStrategy strategy = CompletionStrategySelector.getDefault();
	
	public AGGController(Element root) {
		super(ModelFormat.GGX, root);
	}

	@Override
	public boolean launch() throws Exception {
    	DefaultGraTraImpl gratraDefault;
        LayeredGraTraImpl gratraLayered;
        
    	if(graphGrammar.getGraTraOptions().contains("layered")) {
    		String s = graphGrammar.getName()+"_layered";
    		graphGrammar.setName(s);
//    	 	Create layered graph transformation
    		gratraLayered = new LayeredGraTraImpl();
    		gratraLayered.setGraGra(graphGrammar);
    		gratraLayered.setHostGraph(graphGrammar.getGraph());
    		gratraLayered.setCompletionStrategy(strategy);
    		gratraLayered.setGraTraOptions(graphGrammar.getGraTraOptions());
    		gratraLayered.addGraTraListener(this);
    		System.out.println("\n### Transform layered  gragra:  "+graphGrammar.getName());
    		System.out.println(graphGrammar.getGraTraOptions());
    		gratraLayered.transform();
    	}
    	else {
    		// Create default non-deterministic graph transformation
//    		 Create default graph transformation
    		gratraDefault = new DefaultGraTraImpl();
    		gratraDefault.setGraGra(graphGrammar);
    		gratraDefault.setHostGraph(graphGrammar.getGraph());
    		gratraDefault.setCompletionStrategy(strategy);
    		gratraDefault.setGraTraOptions(graphGrammar.getGraTraOptions());
    		gratraDefault.addGraTraListener(this);
    		System.out.println("\n### Transform  non-deterministically:  "+graphGrammar.getName());
    		gratraDefault.transform();
    	}
		return result.isSucceed;
	}

	@Override
	public void graTraEventOccurred(GraTraEvent e) {
		String ruleName = "";
    	int msgGraTra = e.getMessage();
    	if ((msgGraTra == GraTraEvent.PARAMETER_NOT_SET)){
    	}
    	else if((msgGraTra == GraTraEvent.STEP_COMPLETED)) {
    		ruleName = e.getMatch().getRule().getName();
    		System.out.println(ruleName+"  is applied");
    	}
    	else if (msgGraTra == GraTraEvent.NO_COMPLETION) {
    		ruleName = e.getMatch().getRule().getName();
    		System.out.println(ruleName+"  has no more completion");
    	}
    	else if (msgGraTra == GraTraEvent.CANNOT_TRANSFORM){
    		ruleName = e.getMatch().getRule().getName();
    		System.out.println(ruleName+"  cannot transform");
    	}
    	else if (msgGraTra == GraTraEvent.TRANSFORM_FINISHED) {
    		System.out.println("Transformation finished");
    		result.targetModel = graphGrammar;
    		result.isSucceed = true;
    	}
	}

	@Override
	protected boolean init() {
		BaseFactory bf = BaseFactory.theFactory();
		graphGrammar = bf.createGraGra();
		String filepath = tconf.props.getProperty(TransDescriptor.TRANS_FILE_PATH);
		result.targetModelType = result.targetModel = filepath;
		graphGrammar.load(filepath);
		Vector<String> gratraOptions = new Vector<String>();
    	gratraOptions.add("CSP");
    	gratraOptions.add("injective");
    	gratraOptions.add("dangling");
    	gratraOptions.add("NACs");
    	gratraOptions.add("consistency");
		gratraOptions.add("layered");
    	graphGrammar.setGraTraOptions(gratraOptions);
		return true;
	}

	@Override
	protected boolean loadModel(TResult result, ModelSpec ms) {
		if(result.modelFormat == ModelFormat.GGX)
			graphGrammar = (GraGra) ms.model;
		else if(result.modelFormat == ModelFormat.PKUMT){
			try {
				Utility.PKUMT2GGX(result, graphGrammar);
			} catch (TypeException e) {
				e.printStackTrace();
				return false;
			}
		}else if(result.modelFormat == ModelFormat.EMF){
			return false;
		}else return false;
		return true;
	}

	@Override
	protected boolean loadModel(ModelSpec ms) {
		graphGrammar.load(ms.filePath);
		return true;
	}

	@Override
	protected boolean saveModel() {
		String fn = tconf.props.getProperty("output");
		if(fn!=null&&!fn.equals("")){
			graphGrammar.save(fn);
			return true;
		}else return false;
	}
}
